package com.firexxx.vp.application;

import com.firexxx.common.event.EventPublisher;
import com.firexxx.vp.application.dto.AudioDto;
import com.firexxx.vp.application.dto.StbDto;
import com.firexxx.vp.application.dto.VPMatchDto;
import com.firexxx.vp.application.thread.StbRegisterThread;
import com.firexxx.vp.domain.audio.AudioEntity;
import com.firexxx.vp.domain.stb.*;
import com.firexxx.vp.domain.stb.query.StbQueryInterface;
import com.firexxx.vp.domain.vp.VoicePrintModel;
import com.firexxx.vp.domain.vp.fuse.FuseVoicePrintEntity;
import com.firexxx.vp.domain.vp.fuse.FuseVoicePrintRepository;
import com.firexxx.vp.domain.vp.single.SingleVoicePrintEntity;
import com.firexxx.vp.domain.vp.single.SingleVoicePrintFinishedEvent;
import com.firexxx.vp.domain.vp.single.SingleVoicePrintRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @description: 分类风格命令处理器，每个public方法对应一个unit of work
 * @throws:
 * @author: zhuangzhang2
 * @date: 2019/12/25 09:08
 */
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class StbCommandService {

    @Autowired
    private StbQueryInterface stbQueryInterface;

    @Autowired
    private StbRepository stbRepository;

    @Autowired
    private SingleVoicePrintRepository singleVoicePrintRepository;

    @Autowired
    private FuseVoicePrintRepository fuseVoicePrintRepository;

    @Autowired
    private StbService stbService;

    @Autowired
    private StbRegisterThread stbRegisterThread;

//    @Autowired
//    private RedisTemplate redisTemplate;

//    public StbEntity test() {
////        stbRepository.findById(31L).get().getStbKey();
////
////        int a = 1;
////        a = 2;
//
//        StbEntity stbEntity = stbRepository.findAll().get(0);
//        stbEntity.setUserGroupId("1111");
//
//        return stbEntity;
//
////        EventPublisher.publishEvent(new TestEvent(stbEntity));
//    }

//    public void test1(StbEntity stbEntity) {
//        stbEntity.setUserGroupId("2222");
//    }

    private StbEntity getStb(StbDto stbDto) throws IOException {
        StbEntity stbEntity = stbQueryInterface.getOneByStbKey(
                new StbKey(stbDto.getChannelId(), stbDto.getStbId(), stbDto.getMac()));
        if (stbEntity == null) {
            stbEntity = new StbEntity(stbDto.getChannelId(), stbDto.getStbId(), stbDto.getMac());

            stbRepository.save(stbEntity);

            EventPublisher.publishEvent(new StbCreatedEvent(stbEntity));

            log.info("新建stb:{}", stbEntity.getStbKey());
        }

        return stbEntity;
    }

    public VPMatchDto match(StbDto stbDto, AudioDto audioDto) throws Throwable {
        //获取领域实体
        StbEntity stbEntity = getStb(stbDto);
        AudioEntity audioEntity = new AudioEntity(stbEntity.getStbKey(), audioDto.getAudioId(),
                audioDto.getAudioType(), audioDto.getContent());
        SingleVoicePrintEntity singleVoicePrintEntity = new SingleVoicePrintEntity(audioEntity);

        //调用领域服务
        VoicePrintModel vpModel = stbService.match(stbEntity, singleVoicePrintEntity);

        //持久化数据
        singleVoicePrintRepository.save(singleVoicePrintEntity);

        //发布事件
        EventPublisher.publishEvent(new SingleVoicePrintFinishedEvent(singleVoicePrintEntity));

        return VPMatchDto.from(vpModel);
    }

    public void register(StbDto stbDto) throws Throwable {
        //获取领域实体
        StbEntity stbEntity = getStb(stbDto);

        //调用领域服务
        List<FuseVoicePrintEntity> newFuseVoicePrintList = stbService.clusterByAudioGroup(stbDto.getTraceId(), stbEntity);
        if (newFuseVoicePrintList == null) {
            log.info("stb:{}未生成有效的注册声纹", stbEntity.getStbKey());
            return;
        }

        //持久化
        List<String> fuseVoicePrintIdList = new ArrayList<>();
        for (FuseVoicePrintEntity fuseVoicePrintEntity : newFuseVoicePrintList) {
            fuseVoicePrintRepository.save(fuseVoicePrintEntity);
            fuseVoicePrintIdList.add(fuseVoicePrintEntity.getVpModel().getVpId());
            //发布事件
//            EventPublisher.publishEvent(new FuseVoicePrintFinishedEvent(fuseVoicePrintEntity));
        }
        stbEntity = stbRepository.findById(stbEntity.getId()).get();
        stbEntity.updateGroup(stbDto.getTraceId(), fuseVoicePrintIdList);

//        log.error("------init {}:{}", stbDto.getTraceId(), stbEntity.getVersion());

        stbRepository.save(stbEntity);

//        log.error("------save {}:{}", stbDto.getTraceId(), stbEntity.getVersion());

        //发布事件
        Map<String, Object> map = new HashMap<>();
        map.put("stbEntity", stbEntity);
        map.put("newFuseVoicePrintList", newFuseVoicePrintList);

//        log.error("------ready to publish {}:{}", stbDto.getTraceId(), stbEntity.getVersion());

        EventPublisher.publishEvent(new StbRegisterFinishedEvent(map));
    }

    public void registerStb(StbDto stbDto) throws Throwable {
        if (!stbRegisterThread.getQueue().isEmpty()) {
            log.error("声纹注册队列非空");

            return;
        }

        register(stbDto);
    }

}